/*
**************************************************************************************
*Myriad Engine                                                                       *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
package leola.frontend.parsers;

import static leola.frontend.tokens.LeolaTokenType.COMMA;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;

import leola.ast.ASTNode;
import leola.ast.Expr;
import leola.frontend.Parser;
import leola.frontend.Token;
import leola.frontend.tokens.LeolaErrorCode;
import leola.frontend.tokens.LeolaTokenType;

/**
 * Parsing rules that do not return an {@link ASTNode}
 * 
 * @author Tony
 *
 */
public class ParserUtils {

    // Set of additive operators.
    private static final EnumSet<LeolaTokenType> PARAM_OPS =
        EnumSet.of(LeolaTokenType.COMMA, LeolaTokenType.IDENTIFIER); // do to allow expr
	
    
    /**
     * Parse the actual parameters of a procedure or function call.
     * @param token the current token.
     */
    public static Expr[] parseActualParameters(StmtParser parser
    										 , Token currentToken
    										 , EnumSet<LeolaTokenType> commaDelimeter
    										 , LeolaTokenType endToken) throws Exception
    {
        ExprParser expressionParser = new ExprParser(parser);

        Token token = parser.nextToken();  // consume opening (

        List<Expr> paramsNode = new ArrayList<Expr>();
        
        // Loop to parse each actual parameter.
        while (token.getType() != endToken) {
            ASTNode actualNode = expressionParser.parse(token);                       
            paramsNode.add( (Expr)actualNode);
            
            token = parser.synchronize(commaDelimeter);
            LeolaTokenType tokenType = token.getType();

            // Look for the comma.
            if (tokenType == COMMA) {
                token = parser.nextToken();  // consume ,
            }
            else if (ExprParser.EXPR_START_SET.contains(tokenType)) {
            	parser.getExceptionHandler().errorToken(token, parser, LeolaErrorCode.MISSING_COMMA);
            }
            else if (tokenType != endToken) {
                token = parser.synchronize(ExprParser.EXPR_START_SET);
            }
        }

        token = parser.nextToken();  // consume closing )

        return paramsNode.toArray(new Expr[0]);
    }
	
    /**
	 * Parses a parameter listings
	 * 
	 * @param next
	 * @return
	 * @throws Exception
	 */
	public static String[] parseParameterListings(Parser parser, Token next) throws Exception {
		LeolaTokenType type = next.getType(); 
		
		/* If the is no left brace, fail */
		if ( ! type.equals(LeolaTokenType.LEFT_PAREN)) {
			parser.getExceptionHandler().errorToken(next, parser, LeolaErrorCode.MISSING_LEFT_PAREN);
		}
		
		next = parser.nextToken(); // consume the (	
		type = next.getType(); 
		
		List<String> parameters = new ArrayList<String>();
				
		boolean needsComma = false;
		while(PARAM_OPS.contains(type)) {
			if ( type.equals(LeolaTokenType.IDENTIFIER)) {
				String paramName = next.getText();
				parameters.add(paramName);
				
				next = parser.nextToken();
				type = next.getType();
				
				needsComma = true;
			}
			else if ( type.equals(LeolaTokenType.COMMA)) {
				next = parser.nextToken();
				type = next.getType();
				
				needsComma = false;
			}
			
			Token currentToken = parser.currentToken();
			if ( currentToken.getType().equals(LeolaTokenType.RIGHT_PAREN)) {
				needsComma = false;
			}
			
			if ( ! PARAM_OPS.contains(type) && needsComma ) {
				parser.getExceptionHandler().errorToken(next, parser, LeolaErrorCode.MISSING_COMMA);
			}
		}
		
		if ( !type.equals(LeolaTokenType.RIGHT_PAREN)) {
			parser.getExceptionHandler().errorToken(next, parser, LeolaErrorCode.MISSING_RIGHT_PAREN);
		}
		
		next = parser.nextToken(); // eat the )
		
		
		return parameters.toArray(new String[0]);
	}
    
	/**
	 * Parses the class name.
	 * 
	 * @param token
	 * @return
	 * @throws Exception
	 */
	public static String parseClassName(Parser parser, Token token, LeolaTokenType ... endTokenTypes) throws Exception {
		EnumSet<LeolaTokenType> quitSet = EnumSet.copyOf(Arrays.asList(endTokenTypes));
			
		
		String className = "";
				
		LeolaTokenType type = token.getType(); 
		while(! quitSet.contains(type) ) {
			if ( type.equals(LeolaTokenType.IDENTIFIER) ) {
				className += token.getText();
			}
			else if ( type.equals(LeolaTokenType.DOT)) {
				className += ".";
			}
			else {
				parser.getExceptionHandler().errorToken(token, parser, LeolaErrorCode.UNEXPECTED_TOKEN);
			}
			
			token = parser.nextToken();
			type = token.getType();
		}
		
		return className;
	}
}
